home *** CD-ROM | disk | FTP | other *** search
- ;* SB.ASM
- ;*
- ;* Sound Blaster series Sound Device
- ;*
- ;* $Id: sb.asm,v 1.5 1997/01/16 18:41:59 pekangas Exp $
- ;*
- ;* Copyright 1996,1997 Housemarque Inc.
- ;*
- ;* This file is part of the MIDAS Sound System, and may only be
- ;* used, modified and distributed under the terms of the MIDAS
- ;* Sound System license, LICENSE.TXT. By continuing to use,
- ;* modify or distribute this file you indicate that you have
- ;* read the license and understand and accept it fully.
- ;*
-
-
-
- IDEAL
- P386
- JUMPS
-
- INCLUDE "lang.inc"
- INCLUDE "errors.inc"
- INCLUDE "sdevice.inc"
- INCLUDE "dsm.inc"
- INCLUDE "dma.inc"
- INCLUDE "mixsd.inc"
- INCLUDE "mutils.inc"
-
-
- SB_RESETDELAY = 64 ; Delay for SB reset. According to SDK 8 should be
- ; enough but doesn't seem so on my P90 (PK)
-
-
-
- ;/***************************************************************************\
- ;* enum sbFunctIDs
- ;* ----------------
- ;* Description: ID numbers for SB Sound Device functions
- ;\***************************************************************************/
-
- enum sbFunctIDs \
- ID_sbDetect = ID_sb, \
- ID_sbInit, \
- ID_sbClose
-
-
-
- ;/***************************************************************************\
- ;* ENUM sbCardTypes
- ;* ----------------
- ;* Description: Sound Card type number for SB Sound Device
- ;\***************************************************************************/
-
- ENUM sbCardTypes \
- sbAutoType = 0, \ ; autodetect card type
- sb10, \ ; Sound Blaster 1.0 (DSP v1.xx)
- sb15, \ ; Sound Blaster 1.5 (DSP v2.00)
- sb20, \ ; Sound Blaster 2.0 (DSP v2.01)
- sbPro, \ ; Sound Blaster Pro (DSP v3.xx)
- sb16 ; Sound Blaster 16 (DSP v4.00+)
-
-
-
- DATASEG
-
- D_farptr oldIRQ ; old IRQ vector
- D_int sb22C ; SB DSP data port (2xCh)
- D_int sbTimeConstant ; SB Transfer Time Constant
- D_int sbRate ; SB actual playing rate
- D_int sbVersion ; DSP version number
- D_int sbMode ; actual output mode
- D_int sbInterrupt ; IRQ interrupt number
- D_int sbBlockLength ; DSP playing block length
- D_int sbStereoOK ; flag used by sbSetStereo()
-
- sbStereoDMABuffer dmaBuffer ? ; dummy DMA buffer used to play one
- ; byte with DMA before starting with
- ; SB Pro cards to get left and right
- ; channel the right way
-
- convBuffer DB 4 DUP (?) ; string to number conversion buffer
- oldIRQMask DB ? ; old IRQ mask
- sbOutputFilter DB ? ; initial output filter status
-
-
-
- IFDEF __PASCAL__
- EXTRN SB : SoundDevice ; Sound Device for Pascal version
- ENDIF
-
-
-
-
- IDATASEG
-
-
- SBCONFIGBITS = sdUsePort or sdUseIRQ or sdUseDMA or sdUseMixRate or \
- sdUseOutputMode or sdUseDSM
- SBMODEBITS = sdMono or sdStereo or sd8bit or sd16bit
-
- ; If compiling for Pascal, Sound Device name is sbSD, from which the data
- ; will be copied to Sound Device SB, defined in Pascal.
-
- IFDEF __PASCAL__
- SDNAM equ sbSD
- ELSE
- SDNAM equ SB
- ENDIF
-
- GLOBAL SDNAM : SoundDevice
-
- SDNAM SoundDevice < \
- 0,\
- SBCONFIGBITS,\
- 220h, 7, 1,\
- sbAutoType, 5,\
- SBMODEBITS,\
- ptr_to sbSDName,\
- ptr_to sbCardNames,\
- 4, ptr_to sbPortAddresses,\
- ptr_to sbDetect,\
- ptr_to sbInit,\
- ptr_to sbClose,\
- ptr_to dsmGetMixRate,\
- ptr_to mixsdGetMode,\
- ptr_to mixsdOpenChannels,\
- ptr_to dsmCloseChannels,\
- ptr_to dsmClearChannels,\
- ptr_to dsmMute,\
- ptr_to dsmPause,\
- ptr_to dsmSetMasterVolume,\
- ptr_to dsmGetMasterVolume,\
- ptr_to mixsdSetAmplification,\
- ptr_to mixsdGetAmplification,\
- ptr_to dsmPlaySound,\
- ptr_to dsmReleaseSound\
- ptr_to dsmStopSound,\
- ptr_to dsmSetRate,\
- ptr_to dsmGetRate,\
- ptr_to dsmSetVolume,\
- ptr_to dsmGetVolume,\
- ptr_to dsmSetSample,\
- ptr_to dsmGetSample,\
- ptr_to dsmSetPosition,\
- ptr_to dsmGetPosition,\
- ptr_to dsmGetDirection,\
- ptr_to dsmSetPanning,\
- ptr_to dsmGetPanning,\
- ptr_to dsmMuteChannel,\
- ptr_to dsmAddSample,\
- ptr_to dsmRemoveSample,\
- ptr_to mixsdSetUpdRate,\
- ptr_to mixsdStartPlay,\
- ptr_to mixsdPlay >
-
- sbSDName DB "Sound Blaster series Sound Device v2.21",0
-
- ; *!!*
- sbCardNames DD ptr_to sb10Name
- DD ptr_to sb15Name
- DD ptr_to sb20Name
- DD ptr_to sbProName
- DD ptr_to sb16Name
-
- sb10Name DB "Sound Blaster 1.0 or clone (DSP v1.xx)", 0
- sb15Name DB "Sound Blaster 1.5 (DSP v2.00)", 0
- sb20Name DB "Sound Blaster 2.0 (DSP v2.01)", 0
- sbProName DB "Sound Blaster Pro (DSP v3.xx)", 0
- sb16Name DB "Sound Blaster 16 (DSP v4.00+)", 0
-
- IFDEF __16__
- sbPortAddresses DW 210h, 220h, 230h, 240h, 250h, 260h
- ELSE
- sbPortAddresses DD 210h, 220h, 230h, 240h, 250h, 260h
- ENDIF
-
- blasterStr DB "BLASTER", 0
-
-
-
- CODESEG
-
-
-
- PUBLIC sbDetect
- PUBLIC sbInit
- PUBLIC sbClose
-
-
-
-
- ;/***************************************************************************\
- ;*
- ;* Function: sbWait
- ;*
- ;* Description: Waits until data can be written to the DSP command/data port
- ;* 2xCh
- ;*
- ;* Returns: MIDAS error code
- ;*
- ;* Destroys: _ax, _cx, _dx. _dx now contains the DSP command/data port
- ;* value, 2xCh.
- ;*
- ;\***************************************************************************/
-
- PROC NOLANGUAGE sbWait NEAR
-
- mov _dx,[sb22C]
- mov _cx,0FFFFh
-
- @@wait:
- in al,dx ; read port 22Ch
- test al,al ; is bit 7 set?
- jns @@ok ; if not, DSP is ready
- loop @@wait ; read maximum of 0FFFFh times
-
-
- ; The bit is still set after 0FFFFh reads, so apparently the DSP
- ; is for some reason locked up. Return error.
-
- mov _ax,errSDFailure ; Sound Device hardware failure
- jmp @@done
-
- @@ok:
- xor _ax,_ax
-
- @@done:
- ret
- ENDP
-
-
-
-
- ;/***************************************************************************\
- ;*
- ;* Macro: SBCMD
- ;*
- ;* Description: Writes a command to SB's DSP. Jumps to label @@err if an
- ;* error occurs, with the error code in ax
- ;*
- ;* Input: command command
- ;*
- ;* Destroys: see function sbCommand
- ;*
- ;\***************************************************************************/
-
- MACRO SBCMD command
- mov bl,command
- call sbCommand
- test _ax,_ax
- jnz @@err
- ENDM
-
-
-
-
- ;/***************************************************************************\
- ;*
- ;* Function: sbCommand
- ;*
- ;* Description: Writes a command to SB's DSP
- ;*
- ;* Input: bl command
- ;*
- ;* Returns: MIDAS error code in _ax
- ;*
- ;* Destroys: _ax, _dx, _cx
- ;*
- ;\***************************************************************************/
-
- PROC NOLANGUAGE sbCommand NEAR
-
- call sbWait ; wait until data or command can be
- test _ax,_ax ; written to the DSP
- jnz @@done
-
- mov al,bl ; write the command
- out dx,al
-
- xor _ax,_ax
-
- @@done:
- ret
- ENDP
-
-
-
-
- ;/***************************************************************************\
- ;*
- ;* Function: sbRead
- ;*
- ;* Description: Reads a byte from the DSP data port
- ;*
- ;* Returns: bl byte read
- ;* _ax MIDAS error copde
- ;*
- ;* Destroys: _ax, _cx, _dx
- ;*
- ;\***************************************************************************/
-
- PROC NOLANGUAGE sbRead NEAR
-
- mov _dx,[SB.port]
- add _dx,0Eh ; dx = 2xEh = SB DSP Data Available
- mov _cx,0FFFFh ; port
- @@wait:
- in al,dx
- test al,al ; wait until bit 7 is set
- js @@dok
- loop @@wait
-
- ; Read port 2xEh 65535 time and bit 7 is still zero - failure
- mov _ax,errSDFailure
- jmp @@done
-
- @@dok: add _dx,0Ah-0Eh ; dx = 2xAh = SB DSP Data port
- in al,dx ; read data from port
- mov bl,al ; and store it in bl
-
- xor _ax,_ax ; success
-
- @@done:
- ret
- ENDP
-
-
-
-
- ;/***************************************************************************\
- ;*
- ;* Function: sbReset
- ;*
- ;* Description: Resets the Sound Blaster DSP
- ;*
- ;\***************************************************************************/
-
- PROC sbReset NEAR
-
- mov _dx,[SB.port]
- add _dx,6
- mov al,1 ; reset SB DSP by first writing 1 to
- out dx,al ; port 2x6h
- mov _cx,SB_RESETDELAY
- @@delay:
- in al,dx ; wait for a while (3 usecs)
- loop @@delay
- xor al,al ; and write 0 to port 2x6h
- out dx,al
-
- mov _dx,[SB.port]
- add _dx,0Eh ; SB data available port 2xEh
- mov _cx,1000
-
- @@wd1: in al,dx
- test al,al
- js @@ok1 ; wait until bit 7 (data available)
- loop @@wd1 ; is 1 or 1000 times
- jmp @@err ; no data - no SB
-
- @@ok1: add _dx,0Ah-0Eh ; read data port (2xAh)
- mov _cx,1000
-
- @@wd2: in al,dx
- cmp al,0AAh ; wait until data is 0AAh or 1000
- je @@sbok ; times
- loop @@wd2
- jmp @@err ; no 0AAh - no SB
-
- @@sbok:
- xor _ax,_ax ; SB resetted succesfully
- jmp @@done
-
- @@err:
- mov _ax,errSDFailure
-
- @@done:
- ret
- ENDP
-
-
-
-
- ;/***************************************************************************\
- ;*
- ;* Function: sbGetVersion
- ;*
- ;* Description: Get Sound Blaster DSP version and set up SB.cardType,
- ;* sbVersion and SB.modes accordingly
- ;*
- ;\***************************************************************************/
-
- PROC NOLANGUAGE sbGetVersion NEAR
-
- SBCMD 0E1h ; Get DSP version number
- call sbRead ; read version high byte
- test _ax,_ax
- jnz @@err
- mov bh,bl
- call sbRead ; read version low byte
- test _ax,_ax
- jnz @@err
- mov [sbVersion],_bx ; store version number
-
- cmp _bx,200h ; DSP version < 2.00?
- jb @@sb10 ; if yes, SB version 1.0
- cmp _bx,200h ; DSP version 2.00?
- je @@sb15 ; if yes, SB version 1.5
- cmp _bx,300h ; DSP version < 3.00?
- jb @@sb20 ; if yes, SB version 2.0
- cmp _bx,400h ; DSP version < 4.00?
- jb @@sbPro ; if yes, SB Pro
-
- ; DSP version >= 4.00 - Sound Blaster 16
- mov [SB.cardType],sb16
- mov [SB.modes],sdMono or sdStereo or sd8bit or sd16bit
- jmp @@ok
-
- @@sb10:
- ; SB version 1.0
- mov [SB.cardType],sb10
- mov [SB.modes],sdMono or sd8bit
- jmp @@ok
-
- @@sb15:
- ; SB version 1.5
- mov [SB.cardType],sb15
- mov [SB.modes],sdMono or sd8bit
- jmp @@ok
-
- @@sb20:
- ; SB version 2.0
- mov [SB.cardType],sb20
- mov [SB.modes],sdMono or sd8bit
- jmp @@ok
-
- @@sbPro:
- ; SB Pro
- mov [SB.cardType],sbPro
- mov [SB.modes],sdMono or sdStereo or sd8bit
-
- @@ok:
- xor _ax,_ax
-
- @@err:
- ret
- ENDP
-
-
-
- ;/***************************************************************************\
- ;*
- ;* Function: int sbDetect(int *result);
- ;*
- ;* Description: Detects Sound Blaster soundcard
- ;*
- ;* Returns: MIDAS error code.
- ;* 1 stored to *result if SB was detected, 0 if not.
- ;*
- ;\***************************************************************************/
-
- PROC sbDetect _funct result : _ptr
- USES _si,_di,_bx
- LOCAL port : _int, IRQ : _int, DMA : _int, highDMA : _int
-
- ; Search for "BLASTER" environment string:
- IFDEF __16__
- call mGetEnv LANG, seg blasterStr offset blasterStr
- mov bx,dx ; was "BLASTER" environment found?
- or bx,ax ; if not, no SB
- jz @@nosb
-
- mov es,dx ; point es:si to environment
- mov si,ax ; string
-
- ELSE
- call mGetEnv LANG, offset blasterStr
- test eax,eax ; was "BLASTER" environment found?
- jz @@nosb ; if not, no SB
- jz @@nosb
-
- mov esi,eax ; point _essi to environment string
-
- ENDIF
- mov [port],-1 ; no port found
- mov [IRQ],-1 ; no IRQ found
- mov [DMA],-1 ; no DMA found
- mov [highDMA],-1 ; no High DMA found
-
- @@envloop:
- mov al,[_essi] ; get character from string
- inc _si
- test al,al ; end of string?
- jz @@strend
-
- and al,not 20h ; convert to uppercase if a letter
-
- cmp al,'A' ; Axxx - port address
- je @@port
-
- cmp al,'I' ; Ix - IRQ number
- je @@irq
-
- cmp al,'D' ; Dx - DMA channel number
- je @@dma
-
- cmp al,'H' ; Hx - High DMA channel number
- je @@highdma
-
- jmp @@envloop
-
-
- @@port:
- ; port - the following characters up to next space or \0, maximum
- ; 3, are the I/O port number in hexadecimal
-
- mov _cx,4
- mov _di,offset convBuffer
-
- @@ploop:
- mov al,[_essi]
- inc _si
- cmp al,' '
- je @@port1
- test al,al
- jz @@port1
- mov [_di],al ; copy port number to conversion
- inc _di ; buffer
- loop @@ploop ; max 3 characters
-
- jmp @@nosb ; over 3 characters - bad environment
-
- @@port1:
- mov [byte _di],0 ; append terminating zero
-
- ; convert hex string to number:
- push es
- IFDEF __16__
- call mHex2Long LANG, seg convBuffer offset convBuffer
- ELSE
- call mHex2Long LANG, offset convBuffer
- ENDIF
- pop es
- cmp _ax,-1
- je @@nosb
-
- mov [port],_ax
- jmp @@envloop
-
-
- @@irq:
- ; IRQ - the following characters up to next space or \0, maximum
- ; 2, are the IRQ number in decimal
-
- xor _ax,_ax
- mov al,[_essi] ; get first character
- inc _si
- cmp al,'0' ; below '0'?
- jb @@nosb ; if is, bad environment
- sub al,'0'
-
- xor _bx,_bx
- mov bl,[_essi] ; next character
- cmp bl,' ' ; space?
- je @@irq1
- test bl,bl ; terminating zero?
- jz @@irq1
- cmp bl,'0' ; below '0'?
- jb @@nosb ; if is, bad environment
- sub bl,'0'
- imul _ax,_ax,10 ; IRQ = 10*first + second
- add _ax,_bx
-
- @@irq1:
- mov [IRQ],_ax
- jmp @@envloop
-
-
- @@dma:
- ; DMA - the following character is the DMA channel number
- xor _ax,_ax
- mov al,[_essi] ; get first character
- inc _si
- cmp al,'0' ; below '0'?
- jb @@nosb ; if is, bad environment
- sub al,'0'
- mov [DMA],_ax
- jmp @@envloop
-
-
- @@highdma:
- ; High DMA - the following character is the High DMA channel number
- xor _ax,_ax
- mov al,[_essi] ; get first character
- inc _si
- cmp al,'0' ; below '0'?
- jb @@nosb ; if is, bad environment
- sub al,'0'
- mov [highDMA],_ax
- jmp @@envloop
-
-
- @@strend:
- ; End of environment string. If port, IRQ or DMA value was not found,
- ; the environment string is bad
- cmp [port],-1
- je @@nosb
- cmp [IRQ],-1
- je @@nosb
-
- cmp [highDMA],-1 ; was high DMA channel number found?
- jne @@high1
-
- cmp [DMA],-1 ; no, use normal DMA
- je @@nosb
- jmp @@set
-
- @@high1:
- ; High DMA channel number was found - use it as DMA channel
- mov _ax,[highDMA]
- mov [DMA],_ax
-
- @@set:
- ; Set detected values to card structure:
- mov _ax,[port]
- mov [SB.port],_ax
- add _ax,0Ch
- mov [sb22C],_ax
- mov _ax,[IRQ]
- mov [SB.IRQ],_ax
- mov _ax,[DMA]
- mov [SB.DMA],_ax
-
- call sbReset ; reset the DSP
- test _ax,_ax
- jnz @@err
-
- cmp [SB.cardType],sbAutoType ; has a card type been set?
- jne @@cardtypeset ; if not, detect it
-
- call sbGetVersion
- test _ax,_ax
- jnz @@err
-
- @@cardtypeset:
- LOADPTR es,_bx,[result]
- mov [_int _esbx],1 ; Sound Blaster was detected
- xor _ax,_ax
- jmp @@done
-
- @@nosb:
- LOADPTR es,_bx,[result]
- mov [_int _esbx],0 ; Sound Blaster not detected
- xor _ax,_ax
- jmp @@done
-
- @@err:
- ERROR ID_sbDetect
-
- @@done:
- ret
- ENDP
-
-
-
-
- ;/***************************************************************************\
- ;*
- ;* Function: int sbInit(unsigned mixRate, unsigned mode);
- ;*
- ;* Description: Initializes Sound Blaster series Sound Device
- ;*
- ;* Input: unsigned mixRate mixing rate
- ;* unsigned mode output mode (see enum sdMode)
- ;*
- ;* Returns: MIDAS error code
- ;*
- ;\***************************************************************************/
-
- PROC sbInit _funct mixRate : _int, mode : _int
- USES _bx
-
- mov _ax,[SB.port]
- add _ax,0Ch ; set sb22C variable to real SB DSP
- mov [sb22C],_ax ; command port
-
- call sbReset ; reset the DSP
- jnz @@err
-
- cmp [SB.cardType],sbAutoType ; has a card type been set?
- jne @@typeset
- call sbGetVersion ; if not, detect it
-
- @@typeset:
- cmp [SB.cardType],sb16 ; Sound Blaster 16?
- je @@modeall ; if yes, all modes supported
- cmp [SB.cardType],sbPro ; Sound Blaster Pro?
- jae @@modestereo ; if yes, stereo is supported
-
- ; normal Sound Blaster - only 8-bit mono
- mov [sbMode],sd8bit or sdMono
- jmp @@moded
-
- @@modestereo:
- ; Sound Blaster Pro - only 8-bit mono or stereo
- mov _ax,sd8bit ; 8-bit output
- test [mode],sdMono ; is mono mode forced?
- jnz @@smono
- or _ax,sdStereo ; no, use stereo
- jmp @@sok
- @@smono:
- or _ax,sdMono ; yes, use mono
- @@sok:
- mov [sbMode],_ax ; store output mode
- jmp @@moded
-
-
- @@modeall:
- ; Sound Blaster 16 - all output modes
- test [mode],sd8bit ; force 8-bit?
- jnz @@8b
- mov _ax,sd16bit ; if not, use 16 bits
- jmp @@bit
- @@8b: mov _ax,sd8bit
-
- @@bit: test [mode],sdMono ; force mono?
- jnz @@mono
- or _ax,sdStereo ; if not, use stereo
- jmp @@mst
- @@mono: or _ax,sdMono
-
- @@mst: mov [sbMode],_ax
-
- @@moded:
- mov _ax,[SB.IRQ]
- cmp al,7 ; IRQ number > 7 ?
- ja @@i8
-
- add al,8 ; no, interrupt number is IRQ+8
- jmp @@ivect
-
- @@i8: add al,70h-8 ; yes, interrupt number is IRQ+68h
-
- @@ivect:
- mov [sbInterrupt],_ax ; save interrupt number
-
- push es
- mov ah,35h
- int 21h ; save old IRQ vector
- mov [_int oldIRQ],_bx
- mov [word oldIRQ+INTSIZE],es
- pop es
-
- mov _ax,[SB.IRQ]
- cmp al,7 ; is IRQ > 7 ?
- ja @@i82
-
- mov cl,al ; no
- in al,21h
- mov [oldIRQMask],al ; save old IRQ mask
- mov bl,not 1
- rol bl,cl ; enable SB's IRQ
- and al,bl
- out 21h,al
- jmp @@idone
-
- @@i82: mov cl,al
- sub cl,8
- in al,0A1h
- mov [oldIRQMask],al ; save old IRQ mask
- mov bl,not 1
- rol bl,cl ; enable SB's IRQ
- and al,bl
- out 0A1h,al
-
- @@idone:
-
- cmp [SB.cardType],sb16 ; Sound Blaster 16?
- jae @@userate ; if so, the sampling rate is directly
- ; used
-
- cmp [SB.cardType],sb20 ; Sound Blaster version < 2.0?
- jb @@limit1 ; if yes, rate limit is 21739Hz
-
- ; Sound Blaster 2.0 or Pro - sampling rate limit is 43478Hz, so the
- ; maximum Time Constant is 233
- mov ecx,233
- jmp @@timeconstant
-
- @@limit1:
- ; Sound Blaster 1.0 or 1.5 - sampling rate limit is 21739Hz, making
- ; the maximum Time Constant 210
- mov ecx,210
-
- @@timeconstant:
- ; Calculate the Transfer Time Constant
- IFDEF __16__
- xor ebx,ebx
- ENDIF
- mov _bx,[mixRate]
- test [sbMode],sdStereo ; use stereo?
- jz @@nostt ; if yes, multiply rate with 2 when
- shl ebx,1 ; calculating Time Constant
-
- @@nostt:
- mov eax,1000000 ; eax = Time Constant =
- xor edx,edx ; 256 - (1000000 / rate)
- div ebx
- neg eax
- add eax,256
-
- test eax,eax
- jns @@non1 ; Time Constant must be nonnegative
- xor eax,eax
-
- @@non1: cmp eax,ecx ; ecx is the maximum Time Constant
- jbe @@noa1
- mov eax,ecx ; limit Time Constant to ecx value
-
- @@noa1: mov [sbTimeConstant],_ax ; store Transfer Time Constant
-
- mov ebx,256
- sub ebx,eax
- mov eax,1000000 ; calculate actual playing rate
- xor edx,edx ; (= 1000000 / (256 - TimeConstant))
- div ebx
-
- test [sbMode],sdStereo ; using stereo?
- jz @@nostt2
- shr eax,1 ; divide with 2 to get rate
-
- @@nostt2:
- mov [sbRate],_ax
- jmp @@initmixsd
-
-
- @@userate:
- ; Sound Blaster 16 - output uses the sampling rate directly
- mov _ax,[mixRate]
- mov [sbRate],_ax
-
-
- @@initmixsd:
- cmp [SB.cardType],sbPro ; if playing stereo on SB Pro
- jne @@dmaok ; set stereo mode and output one
- test [sbMode],sdStereo ; silent byte before starting the
- jz @@dmaok ; actual transfer
-
- call sbSetStereo
- test _ax,_ax
- jnz @@err
-
- @@dmaok:
- ; Take care of common initialization for all mixing Sound Devices:
- push es
- call mixsdInit LANG, [sbRate], [sbMode], [SB.DMA]
- pop es
- test _ax,_ax
- jnz @@err
-
- mov [sbBlockLength],0FFF0h ; set DSP block length to 0FFF0h
- ; samples - autoinit DMA mode takes
- ; care of wrapping
-
- mov _bx,[SB.cardType]
- cmp _bx,sb10 ; Sound Blaster 1.0?
- je @@v100 ; if is, auto-initialize mode is not
- ; available
-
- ; set up interrupt service routine for auto-initialize mode:
- push ds
- mov ah,25h
- mov al,[byte sbInterrupt]
- mov dx,cs
- mov ds,dx
- mov _dx,offset sbAutoinitIRQ
- int 21h
- pop ds
-
- cmp _bx,sb16 ; Sound Blaster 16?
- je @@v400 ; if is, use DSP 4.00 playing mode
- ; for all output modes
-
- cmp _bx,sb20 ; Sound Blaster 2.0 or Pro?
- jae @@v201 ; if is, high-speed output is
- ; available
-
- jmp @@v200
-
-
- @@v100:
- ; Sound Blaster 1.0 - play using mono single-cycle mode
-
- ; set up interrupt service routine for single-cycle mode:
- push ds
- mov ah,25h
- mov al,[byte sbInterrupt]
- mov dx,cs
- mov ds,dx
- mov _dx,offset sbSingleCycleIRQ
- int 21h
- pop ds
-
- ; start playing:
- call sbPlayMonoSingleCycle
- jmp @@playing
-
- @@v200:
- ; Sound Blaster 1.5 - play using mono auto-initialize mode
- call sbPlayMonoAutoinit
- jmp @@playing
-
- @@v201:
- ; Sound Blaster 2.0 or Pro - high-speed output is available
- test [sbMode],sdStereo ; use stereo?
- jnz @@plstereo ; if yes, play using stereo mode
-
- cmp [sbRate],22000 ; is sampling rate over 22000Hz?
- ja @@highspeed ; if is, use high-speed mode
-
- ; Sound Blaster 2.0 or Pro, mono, rate <= 22000Hz - play using mono
- ; auto-initialize mode
- call sbPlayMonoAutoinit
- jmp @@playing
-
- @@highspeed:
- ; Sound Blaster 2.0 or Pro, mono, rate > 22000Hz - play using mono
- ; high-speed (auto-initialize) mode
- call sbPlayMonoHighSpeed
- jmp @@playing
-
- @@plstereo:
- ; Sound Blaster Pro, stereo - play using stereo
- ; high-speed auto-initialize mode
- call sbPlayStereo
- jmp @@playing
-
- @@v400:
- ; Sound Blaster 16 - use DSP v4.00 auto-initialize mode for all output
- ; modes
- call sbPlay400
-
- @@playing:
- test _ax,_ax
- jnz @@err
-
- xor _ax,_ax ; SB succesfully initialized
- jmp @@done
-
- @@sberr:
- mov _ax,errSDFailure ; Hardware failure
-
- @@err: ERROR ID_sbInit
-
- @@done:
- ret
- ENDP
-
-
-
-
- ;/***************************************************************************\
- ;*
- ;* Function: sbPlayMonoSingleCycle
- ;*
- ;* Description: Starts playing the buffer using 8-bit mono Single-Cycle mode
- ;*
- ;\***************************************************************************/
-
- PROC NOLANGUAGE sbPlayMonoSingleCycle NEAR
-
- SBCMD 0D1h ; turn on DAC speaker
- SBCMD 40h ; set Transfer Time Constant
- SBCMD <[byte sbTimeConstant]> ; Time Constant
- SBCMD 14h ; 8-bit PCM output
- SBCMD <[byte sbBlockLength]> ; block length low byte
- SBCMD <[byte sbBlockLength+1]> ; block length high byte
-
- @@err:
- ret
- ENDP
-
-
-
-
- ;/***************************************************************************\
- ;*
- ;* Function: sbSingleCycleIRQ
- ;*
- ;* Description: SB DSP interrupt service routine for 8-bit Single-Cycle mode
- ;*
- ;\***************************************************************************/
-
- PROC NOLANGUAGE sbSingleCycleIRQ
-
- sti
- push _ax
- push _cx
- push _dx ; save all registers that will be
- push ds ; changed
-
- ; FIXME:
- mov ax,DGROUP
- mov ds,ax
-
- SBCMD 14h ; 8-bit PCM output
- SBCMD <[byte sbBlockLength]> ; block length low byte
- SBCMD <[byte sbBlockLength+1]> ; block length high byte
-
- @@err: ; no error handling can be done here
-
- mov _dx,[SB.port]
- add _dx,0Eh ; acknowledge DSP interrupt
- in al,dx
-
- cmp [SB.IRQ],7
- ja @@upirq
-
- mov al,20h ; send End Of Interrupt command to
- out 20h,al ; PIC
- jmp @@done
-
- @@upirq:
- mov al,20h ; send EOI to PIC #2 (IRQ > 7)
- out 0A0h,al
- out 20h,al
-
- @@done:
- pop ds
- pop _dx
- pop _cx
- pop _ax
-
- IFDEF __16__
- iret ; some TASM versions seem to generate
- ELSE ; iret even in 32-bit modes
- iretd
- ENDIF
- ENDP
-
-
-
-
- ;/***************************************************************************\
- ;*
- ;* Function: sbPlayMonoAutoinit
- ;*
- ;* Description: Starts playing the buffer using 8-bit Auto-initialize mode
- ;*
- ;\***************************************************************************/
-
- PROC NOLANGUAGE sbPlayMonoAutoinit NEAR
-
- SBCMD 0D1h ; turn on DAC speaker
- SBCMD 40h ; set DSP Transfer Time Constant
- SBCMD <[byte sbTimeConstant]> ; Transfer Time Constant
- SBCMD 48h ; set DSP transfer block size
- SBCMD <[byte sbBlockLength]> ; block length low byte
- SBCMD <[byte sbBlockLength+1]> ; block length high byte
- SBCMD 1Ch ; start 8-bit PCM output
-
- @@err:
- ret
- ENDP
-
-
-
-
- ;/***************************************************************************\
- ;*
- ;* Function: sbAutoinitIRQ
- ;*
- ;* Description: SB DSP interrupt service routine for 8-bit Auto-initialize
- ;* mode
- ;*
- ;\***************************************************************************/
-
- PROC NOLANGUAGE sbAutoinitIRQ
-
- sti
- push _ax
- push _cx
- push _dx ; save all registers that will be
- push ds ; changed
-
- ; Fixme:
- mov ax,DGROUP
- mov ds,ax
-
- test [sbMode],sd16bit ; 16-bit output mode?
- jnz @@16
-
- mov _dx,[SB.port]
- add _dx,0Eh ; acknowledge DSP interrupt
- in al,dx
- jmp @@ackdone
-
- @@16:
- mov _dx,[SB.port]
- add _dx,0Fh ; acknowledge DSP interrupt
- in al,dx
-
- @@ackdone:
- cmp [SB.IRQ],7
- ja @@upirq
-
- mov al,20h ; send End Of Interrupt command to
- out 20h,al ; PIC
- jmp @@done
-
- @@upirq:
- mov al,20h ; send EOI to PIC #2 (IRQ > 7)
- out 0A0h,al
- out 20h,al
-
- @@done:
- pop ds
- pop _dx
- pop _cx
- pop _ax
-
- IFDEF __16__
- iret ; some TASM versions seem to generate
- ELSE ; iret even in 32-bit modes
- iretd
- ENDIF
- ENDP
-
-
-
-
- ;/***************************************************************************\
- ;*
- ;* Function: sbPlayMonoHighSpeed
- ;*
- ;* Description: Starts playing the buffer using 8-bit mono High-Speed
- ;* Auto-initialize mode
- ;*
- ;\***************************************************************************/
-
- PROC NOLANGUAGE sbPlayMonoHighSpeed NEAR
-
- SBCMD 0D1h ; turn on DAC speaker
- SBCMD 40h ; set DSP transfer Time Constant
- SBCMD <[byte sbTimeConstant]> ; transfer Time Constant
- SBCMD 48h ; set DSP transfer block size
- SBCMD <[byte sbBlockLength]> ; block length low byte
- SBCMD <[byte sbBlockLength+1]> ; block length high byte
- SBCMD 90h ; 8-bit PCM high-speed output
-
- @@err:
- ret
- ENDP
-
-
-
-
- ;/***************************************************************************\
- ;*
- ;* Function: sbSetStereo
- ;*
- ;* Description: Sets the SB hardware to stereo mode and plays a single
- ;* silent byte. Called before starting stereo transfer on
- ;* DSP < 4.00 to make sure that the channels are the right
- ;* way and not reversed (left comes from left and right from
- ;* right). Note that this is not of our own invention, but is
- ;* actually documented in the SDK.
- ;*
- ;\***************************************************************************/
-
- PROC NOLANGUAGE sbSetStereo NEAR
-
- SBCMD 0D1h
-
- mov _dx,[SB.port]
- add _dx,04h
- mov al,0Eh
- out dx,al ; set the mixer to stereo mode
- inc _dx
- in al,dx
- or al,2
- out dx,al
-
- ; set up the IRQ handler for transfer:
- push ds
- mov ah,25h
- mov al,[byte sbInterrupt]
- mov dx,cs
- mov ds,dx
- mov _dx,offset @@irqhandler
- int 21h
- pop ds
-
- ; Set up the DMA buffer for one byte transfer:
- mov [sbStereoDMABuffer.startAddr],0
- mov [sbStereoDMABuffer.bufferLen],0
- mov [sbStereoDMABuffer.channel],-1
-
- ; program the DMA controller for single-cycle output:
- IFDEF __16__
- call dmaPlayBuffer LANG, \
- seg sbStereoDMABuffer offset sbStereoDMABuffer, [SB.DMA], 0
- ELSE
- push es
- call dmaPlayBuffer LANG, offset sbStereoDMABuffer, [SB.DMA], 0
- pop es
- ENDIF
- test _ax,_ax
- jnz @@err
-
- mov [sbStereoOK],0
-
- SBCMD 14h
- SBCMD 0 ; program the DSP to output one
- SBCMD 0 ; silent byte (80h)
-
- ; wait until the IRQ occurs:
- @@w:
- cmp [sbStereoOK],1
- jne @@w
-
- xor _ax,_ax
-
- @@err:
- ret
-
-
- @@irqhandler:
- ; IRQ handler routine:
-
- push _ax
- push _cx
- push _dx ; save all registers that will be
- push ds ; changed
-
- ; FIXME:
- mov ax,DGROUP
- mov ds,ax
-
- mov [sbStereoOK],1 ; set interrupt flag
-
- mov _dx,[SB.port]
- add _dx,0Eh ; acknowledge DSP interrupt
- in al,dx
-
- cmp [SB.IRQ],7
- ja @@upirq
-
- mov al,20h ; send End Of Interrupt command to
- out 20h,al ; PIC
- jmp @@done
-
- @@upirq:
- mov al,20h ; send EOI to PIC #2 (IRQ > 7)
- out 0A0h,al
- out 020h,al
-
- @@done:
- pop ds
- pop _dx
- pop _cx
- pop _ax
-
- IFDEF __16__
- iret
- ELSE
- iretd
- ENDIF
- ENDP
-
-
-
-
- ;/***************************************************************************\
- ;*
- ;* Function: sbPlayStereo
- ;*
- ;* Description: Starts playing the buffer using 8-bit stereo High-Speed
- ;* Auto-initialize mode
- ;*
- ;\***************************************************************************/
-
- PROC NOLANGUAGE sbPlayStereo NEAR
-
- SBCMD 0D1h ; turn on DAC speaker
- SBCMD 40h ; set DSP transfer Time Constant
- SBCMD <[byte sbTimeConstant]> ; transfer Time Constant
-
- ; save output filter status and turn it off:
- mov _dx,[SB.port]
- add _dx,04h
- mov al,0Ch
- out dx,al
- inc _dx
- in al,dx
- mov [sbOutputFilter],al
- or al,20h
- out dx,al
-
- SBCMD 48h ; set DSP transfer block size
- SBCMD <[byte sbBlockLength]> ; block length low byte
- SBCMD <[byte sbBlockLength+1]> ; block length high byte
- SBCMD 90h ; 8-bit PCM high-speed output
-
- @@err:
- ret
- ENDP
-
-
-
-
- ;/***************************************************************************\
- ;*
- ;* Function: sbPlay400
- ;*
- ;* Description: Starts playing the buffer using the DSP 4.00 Auto-initialize
- ;* transfer
- ;*
- ;\***************************************************************************/
-
- PROC NOLANGUAGE sbPlay400 NEAR
-
- SBCMD 41h ; set DSP output sampling rate
- SBCMD <[byte sbRate+1]> ; sampling rate high byte
- SBCMD <[byte sbRate]> ; sampling rate low byte
-
- test [sbMode],sd8bit ; 8-bit mode?
- jnz @@8bit
-
- SBCMD 0B4h ; 16-bit output
- test [sbMode],sdMono ; mono?
- jnz @@mono16
- SBCMD 30h ; 16-bit stereo signed PCM
- jmp @@setlen
- @@mono16:
- SBCMD 10h ; 16-bit mono signed PCM
- jmp @@setlen
-
- @@8bit:
- SBCMD 0C6h ; 8-bit output
- test [sbMode],sdMono ; mono?
- jnz @@mono8
- SBCMD 20h ; 8-bit stereo unsigned PCM
- jmp @@setlen
- @@mono8:
- SBCMD 00h ; 8-bit mono unsigned PCM
-
- @@setlen:
- SBCMD <[byte sbBlockLength]> ; transfer length low byte
- SBCMD <[byte sbBlockLength+1]> ; transfer length high byte
-
- @@err:
- ret
- ENDP
-
-
-
-
- ;/***************************************************************************\
- ;*
- ;* Function: int sbClose(void)
- ;*
- ;* Description: Uninitializes Sound Blaster
- ;*
- ;* Returns: MIDAS error code
- ;*
- ;\***************************************************************************/
-
- PROC sbClose _funct
- USES _bx
-
- ; Reset DSP _twice_ to stop playing and reset it: (In High-Speed mode
- ; the first DSP reset just stops the playing. Besides, this should
- ; not hurt anyone in any output mode anyway.)
- mov _bx,2
- mov _dx,[SB.port]
- add _dx,06h
-
- @@reset:
- mov al,1 ; reset SB DSP by first writing 1 to
- out dx,al ; port 2x6h
- mov _cx,SB_RESETDELAY
- @@delay:
- in al,dx ; wait for a while (3 usecs)
- loop @@delay
- xor al,al ; and write 0 to port 2x6h
- out dx,al
-
- mov _cx,SB_RESETDELAY
- @@delay2: ; another delay
- in al,dx
- loop @@delay2
-
- dec _bx ; and reset again
- jnz @@reset
-
-
- ; Take care of common uninitialization for all mixing Sound Devices:
- push es
- call mixsdClose
- pop es
- test _ax,_ax
- jnz @@err
-
-
- cmp [SB.IRQ],7 ; is IRQ number > 7 ?
- ja @@i8
-
- mov al,[oldIRQMask]
- out 21h,al ; restore old IRQ mask, IRQ <= 7
- jmp @@ivect
-
- @@i8: mov al,[oldIRQMask] ; restore old IRQ mask, IRQ > 7
- out 0A1h,al
-
- @@ivect:
- push ds
- mov al,[byte sbInterrupt]
- mov ah,25h ; restore old IRQ vector
- lds _dx,[oldIRQ]
- int 21h
- pop ds
-
- SBCMD 0D3h ; turn off the DAC speaker
-
- cmp [SB.cardType],sbPro
- jne @@stok ; using stereo on SB Pro?
- test [sbMode],sdStereo
- jz @@stok
-
- ; stereo on SB Pro - restore the output filter status and set
- ; hardware to mono mode:
-
- mov _dx,[SB.port]
- add _dx,04h ; write 04h to port 2x4h
- mov al,0Ch
- out dx,al
- inc _dx
- mov al,[sbOutputFilter] ; write output filter value to 2x5h
- out dx,al
-
- dec _dx
- mov al,0Eh
- out dx,al
- inc _dx ; turn off stereo mode
- in al,dx
- and al,not 02h
- out dx,al
-
- @@stok:
- xor _ax,_ax
- jmp @@done
-
- @@err: ERROR ID_sbClose
-
- @@done:
- ret
- ENDP
-
-
- ;* $Log: sb.asm,v $
- ;* Revision 1.5 1997/01/16 18:41:59 pekangas
- ;* Changed copyright messages to Housemarque
- ;*
- ;* Revision 1.4 1997/01/16 18:27:15 pekangas
- ;* Fixed IRQ acknowledging with IRQs >7 (thanks Statix)
- ;*
- ;* Revision 1.3 1996/10/13 16:55:18 pekangas
- ;* Fixed a bug in detecting IRQs >9
- ;*
- ;* Revision 1.2 1996/08/04 11:33:44 pekangas
- ;* All functions now preserve _bx
- ;*
- ;* Revision 1.1 1996/05/22 20:49:33 pekangas
- ;* Initial revision
- ;*
-
- END